import sys
import getSDCardName
from PyQt5.QtWidgets import *
from functools import partial
from Common import Log
import DialogResult
import subprocess
import os
import shutil
from Common import DownloadThread
from Common import AptInstallThread
from Common import MakeSDThread
from Common import ReadLogThread
from Common import ADKUtils
from USBManager import USBManager
import collections
import configparser
import encodings.idna

class MakeSDCard:

    def __init__(self, ui, sudo_passwd, language):

        # self.project_path = os.path.split(os.path.realpath(__file__))[0]
        # print("project_path = ", self.project_path)
        self.project_path = os.path.dirname(os.path.abspath(sys.argv[0]))
        # print("parent_path = ", parent_dir)

        self.download_path = os.path.join(self.project_path, "makesd")
        self.logfile = os.path.join(self.project_path, "makesdcard.log")

        if os.path.exists(self.logfile):
            shutil.move(self.logfile, self.logfile + ".old")

        self.ui = ui
        self.apt_install_dict = self.ui.apt_install_dict
        self.download_dict = self.ui.download_dict

        self.apt_install_list = self.ui.apt_install_list

        self.comboBox_apt = self.ui.comboBox_apt

        self.comboBox_tar = self.ui.comboBox_tar

        self.logger = Log(self.logfile, __name__).getlog()

        self.logger.info("project dir: " + self.project_path)
        self.logger.info("download dir: " + self.download_path)

        self.sd_ready = False

        self.download_thread_list = []
        self.apt_thread_list = []

        self.sudo_passwd = sudo_passwd

        self.ui.pushButton.setEnabled(False)

        self.apt_all_done = False
        self.download_ok = False
        self.make_sd_not_running = True

        self.language = language
        self.getSDName_ui = getSDCardName.Ui_Dialog()
        self.dialog_getSDName = QDialog()
        self.getSDName_ui.setupUi(self.dialog_getSDName, self.language)
        self.getSDName_ui.pushButton.clicked.connect(self.get_sd_name)
        self.source_flag_dict = collections.OrderedDict()
        self.source_flag_dict["use the default apt-get source"] = [False]
        self.source_flag_dict["use the http://mirrors.huaweicloud.com/ apt-get source"] = [False]
        self.source_flag_dict["use the https://mirrors.tuna.tsinghua.edu.cn/ubuntu/apt-get source"] = [False]
        self.source_flag_dict["use the http://mirrors.aliyun.com/ubuntu/ apt-get source"] = [False]
        self.source_flag_dict["use the http://mirrors.ustc.edu.cn/ubuntu/ apt-get source"] = [False]

    def download(self, key):
        download_url = self.download_dict[key]["url"]
        path = self.download_path
        download_thread = DownloadThread(download_url, path, key,checkBox_tar_update_source=self.comboBox_tar,buffer=10240)
        download_thread.download_progress_signal.connect(self.change_progressbar_value)
        download_thread.download_finished_signal.connect(self.do_download_finished)
        download_thread.start()

        self.download_thread_list.append(download_thread)

    def change_progressbar_value(self, value, key):
        self.download_dict[key]["progressBar"].setValue(value)

    def do_download_finished(self, value, key):
        if value == 2:
            self.download_dict[key]["statusLabel"].setText("failed")
            self.download_dict[key]["progressBar"].setValue(0)
            self.logger.info("%s download failed." % key)
            self.download_dict[key]["download_finished"] = False
        elif value == 1:
            self.download_dict[key]["statusLabel"].setText("download_finished")
            self.download_dict[key]["progressBar"].setValue(100)
            self.logger.info("%s download finished." % key)
            self.download_dict[key]["download_finished"] = True
        elif value == 3:
            self.download_dict[key]["statusLabel"].setText("running")
            self.logger.info("download " + key + " running.")
            self.download_dict[key]["download_finished"] = False
            return
        elif value == 4:
            self.download_dict[key]["statusLabel"].setText("pause")
            self.logger.info("download " + key + " pause.")
            self.download_dict[key]["download_finished"] = False
            return
        self.download_dict[key]["statusLabel"].setVisible(True)

        Flag = True
        for key in self.ui.download_dict:
            if self.ui.download_dict[key]["statusLabel"].text() != "download_finished":
                if self.ui.download_dict[key]["statusLabel"].text() != "failed":
                    Flag = False
        if Flag:
            self.do_download_ok()

    def do_download_ok(self):
        self.download_ok = True

        if self.apt_all_done and self.make_sd_not_running:
            self.make_sd_not_running = False
            self.make_sd_impl()

    def down_packages(self):
        self.logger.info("Begin to download packages...")
        self.download_ok = False
        for key in self.download_dict:
            self.download_dict[key]["download_finished"] = False
            self.download_dict[key]["statusLabel"].setText("")
        for key in self.download_dict:
            self.download(key)

    def do_apt_install(self, key, bFinished):
        self.logger.info("in do_apt_install.")

        if(bFinished):
            self.apt_install_dict[key]["statusLabel"].setText("finished.")
            self.logger.info("install " + key + " finished.")
            self.apt_install_dict[key]["progressBar"].setMaximum(100)
            self.apt_install_dict[key]["progressBar"].setValue(100)
            self.apt_install_dict[key]["isInstalled"] = True
        else:
            self.apt_install_dict[key]["statusLabel"].setText("failed.")
            self.logger.error("install " + key + " failed.")
            self.apt_install_dict[key]["progressBar"].setMaximum(100)
            self.apt_install_dict[key]["progressBar"].setValue(50)

    def do_apt_install_begin(self, key):
        self.apt_install_dict[key]["statusLabel"].setText("running.")
        self.logger.info("install " + key + " begin.")
        self.apt_install_dict[key]["progressBar"].setMaximum(0)
        #self.apt_install_dict[key]["progressBar"].setVale(100)

    def do_apt_update_begin(self, key):
        if key == "update":
            self.ui.apt_update_label.setText("running")
            self.ui.progressBar_apt_update.setMaximum(0)
            self.logger.info("apt-get update begin.")
        else:
            self.logger.info("it's not apt-get update running. ")

    def do_apt_update(self, key, bFinished):
        if key == "update":
            self.logger.info("in do_apt_update.")

            if (bFinished == 1):
                self.ui.apt_update_label.setText("finished.")
                self.logger.info("apt-get " + key + " finished.")
                self.ui.progressBar_apt_update.setMaximum(100)
                self.ui.progressBar_apt_update.setValue(100)
                self.ui.apt_install_dict[key]["isInstalled"] = True
                self.source_flag_dict[self.comboBox_apt.currentText()] = [True]
            elif (bFinished == 2):
                self.ui.apt_update_label.setText("pass")
                self.logger.info("apt-get " + key + " pass.")
                self.ui.progressBar_apt_update.setMaximum(100)
                self.ui.progressBar_apt_update.setValue(100)
            else:
                self.ui.apt_update_label.setText("failed.")
                self.logger.error("install " + key + " failed.")
                self.ui.progressBar_apt_update.setEnabled(True)
                self.ui.progressBar_apt_update.setVisible(True)
                self.ui.progressBar_apt_update.setMaximum(100)
                self.ui.progressBar_apt_update.setValue(50)
                self.ui.pushButton_pause.setVisible(False)
                self.ui.pushButton.setVisible(True)
                self.ui.pushButton.setEnabled(True)
                ADKUtils.disable_item_comboBox(self.ui.comboBox_apt, [0, 1, 2, 3, 4], 1 | 32)
                ADKUtils.disable_item_comboBox(self.ui.comboBox_tar, [0, 1], 1 | 32)

        else:
            self.logger.error("it's not apt-get update. ")
            self.ui.pushButton_pause.setVisible(False)
            self.ui.pushButton.setVisible(True)
            self.ui.pushButton.setEnabled(True)
            ADKUtils.disable_item_comboBox(self.ui.comboBox_apt, [0, 1, 2, 3, 4], 1 | 32)
            ADKUtils.disable_item_comboBox(self.ui.comboBox_tar, [0, 1], 1 | 32)

    def do_apt_already_installed(self, key):
        self.logger.info("in do_apt_already_installed")
        self.apt_install_dict[key]["statusLabel"].setText("already installed.")
        self.logger.info(key + " already installed.")
        self.apt_install_dict[key]["progressBar"].setMaximum(100)
        self.apt_install_dict[key]["progressBar"].setValue(100)
        self.apt_install_dict[key]["isInstalled"] = True

    def apt_install(self):
        apt_thread = AptInstallThread(self.apt_install_list, self.logfile,
                                      checkBox_apt_update_source=self.comboBox_apt, b_sudo=True, passwd=self.sudo_passwd, mylogger=self.logger, source_dict=self.source_flag_dict)

        apt_thread.apt_install_signal.connect(self.do_apt_install)
        apt_thread.apt_install_begin_signal.connect(self.do_apt_install_begin)
        apt_thread.apt_update_begin_signal.connect(self.do_apt_update_begin)
        apt_thread.apt_update_signal.connect(self.do_apt_update)
        apt_thread.apt_already_installed.connect(self.do_apt_already_installed)

        apt_thread.apt_all_have_done.connect(self.do_apt_all_have_done)
        apt_thread.start()

        self.apt_thread_list.append(apt_thread)

    def do_apt_all_have_done(self):
        self.apt_all_done = True
        if self.download_ok and self.make_sd_not_running:
            self.make_sd_not_running = False

            self.make_sd_impl()

    def do_reset(self):
        self.ui.pushButton.setVisible(True)
        self.ui.pushButton.setEnabled(True)

    def is_apt_install_already(self):
        for key in self.apt_install_list:
            if not ADKUtils.is_apt_installed(key):
                self.ui.pushButton.setEnabled(False)
                self.logger.info(key + " not ready.")
                return False
        self.logger.info("all apt install finished.")
        return True

    def is_download_already(self):
        for key in self.download_dict:
            if not self.download_dict[key]["download_finished"]:
                self.logger.info(key + " not ready.")
                return False
        self.logger.info("all package downloaded finished.")
        return True

    def is_all_ready(self):
        if self.is_apt_install_already() and self.is_download_already():
            return True

        return False

    def makesd_prepare(self):

        self.logger.info('Begin preparing for make SD card....')
        (ret, output) = subprocess.getstatusoutput("whoami")
        self.logger.info(output)

        self.ui.progressBar_make_sd.setValue(0)
        self.ui.flashButton.setEnabled(False)
        self.ui.flashButton.setText("Next")
        self.ui.lineEdit_download_path.setReadOnly(True)
        ADKUtils.disable_item_comboBox(self.ui.comboBox_apt, [0, 1, 2, 3, 4], 0)
        ADKUtils.disable_item_comboBox(self.ui.comboBox_tar, [0, 1], 0)
        download_path = self.ui.lineEdit_download_path.text().strip()

        if download_path.startswith('./'):
            self.download_path = os.path.join(self.project_path, download_path[2:])
        else:
            self.download_path = download_path

        if not os.path.isdir(download_path):
            if not self.show_message_with_result(
                    "The download path %s doesn't exist. created for you." % download_path):
                return
            (ret, output) = subprocess.getstatusoutput("mkdir -p " + download_path)
        if not os.path.exists(download_path):
            self.show_message("The download path %s doesn't exist. please check. " % download_path)

        make_ubuntu_sd_sh = os.path.join(self.project_path, "make_ubuntu_sd.sh")

        # shutil.copy(make_ubuntu_sd_sh, self.download_path)
        #subprocess.getstatusoutput("echo " + self.sudo_passwd + " | sudo -S rm make_ubuntu_sd.sh " + download_path)
        ubuntu_sh_dir = os.path.join(download_path, "make_ubuntu_sd.sh")
        if not os.path.exists(ubuntu_sh_dir):
            (ret, output) = subprocess.getstatusoutput("echo " + self.sudo_passwd + " | sudo -S cp make_ubuntu_sd.sh " + download_path)
            if not ret == 0:
                self.logger.error('ERROR, failed to copy make_ubuntu_sd.sh to %s , please check the permission. ' % download_path)
                sys.exit(0)
            else:
                self.logger.info('copy make_ubuntu_sd.sh to the %s success. ' % download_path)

        self.ui.pushButton.setEnabled(False)
        self.ui.pushButton.setVisible(False)

        self.ui.pushButton_pause.setEnabled(True)
        self.ui.pushButton_pause.setVisible(True)

        self.apt_all_done = False
        self.apt_install()

        self.down_packages()

    def show_message_with_result(self, msg):
        dialog_result = QDialog()
        result_ui = DialogResult.Ui_Dialog()
        result_ui.setupUi(dialog_result)
        result_ui.label.setText(msg)
        result_ui.buttonBox.setStandardButtons(QDialogButtonBox.Cancel|QDialogButtonBox.Ok)

        return dialog_result.exec() == QDialog.Accepted

    def update_log(self, msg):
        if msg.find('[ERROR]') != -1:
            msg = "<font color='red'>"+ msg +'</font>'
        self.ui.textBrowser_log.append(msg)
        if msg.find('make_sd_process: 2%') != -1:
            self.ui.progressBar_make_sd.setValue(2)
        if msg.find('make_sd_process: 5%') != -1:
            self.ui.progressBar_make_sd.setValue(5)
        if msg.find('make_sd_process: 10%') != -1:
            self.ui.progressBar_make_sd.setValue(10)
        if msg.find('make_sd_process: 20%') != -1:
            self.ui.progressBar_make_sd.setValue(20)
        if msg.find('make_sd_process: 25%') != -1:
            self.ui.progressBar_make_sd.setValue(25)
        if msg.find('make_sd_process: 30%') != -1:
            self.ui.progressBar_make_sd.setValue(30)
        if msg.find('make_sd_process: 35%') != -1:
            self.ui.progressBar_make_sd.setValue(35)
        if msg.find('make_sd_process: 45%') != -1:
            self.ui.progressBar_make_sd.setValue(45)
        if msg.find('make_sd_process: 50%') != -1:
            self.ui.progressBar_make_sd.setValue(50)
        if msg.find('make_sd_process: 55%') != -1:
            self.ui.progressBar_make_sd.setValue(55)
        if msg.find('make_sd_process: 75%') != -1:
            self.ui.progressBar_make_sd.setValue(75)
        if msg.find('make_sd_process: 80%') != -1:
            self.ui.progressBar_make_sd.setValue(80)
        if msg.find('make_sd_process: 85%') != -1:
            self.ui.progressBar_make_sd.setValue(85)
        if msg.find('make_sd_process: 90%') != -1:
            self.ui.progressBar_make_sd.setValue(90)
        if msg.find('make_sd_process: 95%') != -1:
            self.ui.progressBar_make_sd.setValue(95)
        if msg.find('make_sd_process: 98%') != -1:
            self.ui.progressBar_make_sd.setValue(98)

    def read_log_to_gui(self, logfile):
        # read_log_thread = threading.Thread(target=self.read_log)  # 实例化一个线程
        # read_log_thread.start()
        self.read_log_thread = ReadLogThread(logfile)

        self.read_log_thread.update_log_signal.connect(self.update_log)

        self.read_log_thread.start()

    def show_message(self, msg):
        dialog_result = QDialog()
        result_ui = DialogResult.Ui_Dialog()
        result_ui.setupUi(dialog_result)
        result_ui.label.setText(msg)

        if dialog_result.exec() == QDialog.Accepted:
            self.logger.info(msg)
            return

    def flash_already_runing(self):
        (ret, output) = subprocess.getstatusoutput("ps -ef | grep make_sd_card.py | grep -v grep | wc -l ")
        if int(output) > 0:
            self.logger.info("make sd card is runnning.")
            return True
        else:
            self.logger.info("make sd card is not runnning now.")
            return False

    def do_flash_begin(self):
        # self.ui.progressBar_make_sd.setMinimum(0)
        # self.ui.progressBar_make_sd.setMaximum(0)
        self.show_message("make sd begin, it need 5-10 minutes, please wait.\n don't close the main window.")
        pass

    def do_flash_end(self, b_result):
        if b_result:
            self.ui.progressBar_make_sd.setMaximum(100)
            self.ui.progressBar_make_sd.setValue(100)
            self.ui.flashButton.setVisible(True)
            self.ui.flashButton.setEnabled(True)
            self.ui.pushButton.setVisible(True)
            self.ui.pushButton.setEnabled(True)
            self.show_message("make sd card finished.")
            self.logger.info("make sd card successfully.")
            self.make_sd_not_running = True
            self.ui.lineEdit_download_path.setReadOnly(False)
            ADKUtils.disable_item_comboBox(self.ui.comboBox_apt, [0, 1, 2, 3, 4], 1 | 32)
            ADKUtils.disable_item_comboBox(self.ui.comboBox_tar, [0, 1], 1 | 32)
        else:
            self.ui.progressBar_make_sd.setMaximum(100)
            self.ui.progressBar_make_sd.setValue(10)
            self.ui.pushButton.setVisible(True)
            self.ui.pushButton.setEnabled(True)
            self.ui.flashButton.setVisible(False)
            self.make_sd_not_running = True
            self.show_message("make sd card failed.")
            self.logger.info("make sd card failed.")
            self.ui.lineEdit_download_path.setReadOnly(False)
            ADKUtils.disable_item_comboBox(self.ui.comboBox_apt, [0, 1, 2, 3, 4], 1 | 32)
            ADKUtils.disable_item_comboBox(self.ui.comboBox_tar, [0, 1], 1 | 32)

    def do_flash_sd_card_not_ok(self):
        self.make_sd_not_running = True
        self.ui.lineEdit_download_path.setReadOnly(False)
        ADKUtils.disable_item_comboBox(self.ui.comboBox_apt, [0, 1, 2, 3, 4], 1 | 32)
        ADKUtils.disable_item_comboBox(self.ui.comboBox_tar, [0, 1], 1 | 32)
        self.show_message("sd card not ok, please check log.")

    def flash_impl(self,make_sd_log_file):

        self.log_result = os.path.join(self.project_path, "makesdcard.result")
        self.make_sd_thread = MakeSDThread(self.download_path, self.sd_name, make_sd_log_file, self.log_result,eth0_ip=self.getSDName_ui.comboBox_default_eth0_ip.currentText(), usb_ip=self.getSDName_ui.comboBox_default_usb_ip.currentText(), sudo_passwd=self.sudo_passwd, mylogger=self.logger)
        self.make_sd_thread.make_sd_begin_signal.connect(self.do_flash_begin)
        self.make_sd_thread.make_sd_progress_result.connect(self.do_flash_end)
        self.make_sd_thread.make_sd_card_not_ok.connect(self.do_flash_sd_card_not_ok)
        self.make_sd_thread.start()

    def make_sd_impl(self):
        if not self.is_all_ready():
            self.show_message("still not ready, please wait.")
            self.make_sd_not_running = True
            self.ui.pushButton_pause.setVisible(False)
            self.ui.pushButton_pause.setEnabled(False)
            self.ui.pushButton.setVisible(True)
            self.ui.pushButton.setEnabled(True)
            ADKUtils.disable_item_comboBox(self.ui.comboBox_apt, [0, 1, 2, 3, 4], 1 | 32)
            ADKUtils.disable_item_comboBox(self.ui.comboBox_tar, [0, 1], 1 | 32)
            self.ui.lineEdit_download_path.setReadOnly(False)
            return
        self.ui.pushButton_pause.setVisible(False)
        self.ui.pushButton_pause.setEnabled(False)
        self.ui.pushButton.setVisible(True)
        if self.flash_already_runing():
            self.show_message("flash already running. don't repeat click the button.")
            self.logger.info("flash already running. don't repeat click the button.")
            self.make_sd_not_running = False
            return

        if self.dialog_getSDName.exec() == QDialog.Accepted:
            self.sd_name = self.getSDName_ui.comboBox.currentText()
            if self.sd_name.find('/dev/sd') == 0:
                self.logger.info('get sd name: ' + self.sd_name)
                conf = configparser.ConfigParser()
                conf.read(self.project_path + "/config.ini")
                conf.set("make_sd_info", "usb_ip", self.getSDName_ui.comboBox_default_usb_ip.currentText())
                conf.set("make_sd_info", "eth0_ip", self.getSDName_ui.comboBox_default_eth0_ip.currentText())
                conf.write(open(self.project_path + "/config.ini", "w", encoding="utf-8"))
                str1 = conf.get("make_sd_info", "usb_ip")
                str2 = conf.get("make_sd_info", "eth0_ip")
                self.ui.label_makesd_info.setToolTip("usb_ip" + str1 + "\n" + "eth0_ip" + str2)

                self.sd_ready = True
            else:
                self.sd_ready = False
                self.logger.info('sd name not correct, please check. sd_name = ' + self.sd_name)
                self.show_message('sd name not correct, please check. sd_name = ' + self.sd_name)
                #self.ui.pushButton.setVisible(True)
                self.ui.pushButton.setEnabled(True)
                self.ui.flashButton.setEnabled(True)
                self.ui.flashButton.setText("Skip")
                self.make_sd_not_running = True
                self.ui.lineEdit_download_path.setReadOnly(False)
                ADKUtils.disable_item_comboBox(self.ui.comboBox_apt, [0, 1, 2, 3, 4], 1 | 32)
                ADKUtils.disable_item_comboBox(self.ui.comboBox_tar, [0, 1], 1 | 32)
                return
        else:
            self.logger.info('you canceled, so interrupt, you can retry.')
            self.ui.pushButton.setEnabled(True)
            self.ui.flashButton.setEnabled(True)
            self.ui.flashButton.setText("Skip")
            self.make_sd_not_running = True
            self.ui.lineEdit_download_path.setReadOnly(False)
            ADKUtils.disable_item_comboBox(self.ui.comboBox_apt, [0, 1, 2, 3, 4], 1 | 32)
            ADKUtils.disable_item_comboBox(self.ui.comboBox_tar, [0, 1], 1 | 32)
            return

        self.logger.info("Begin to flash...")
        #self.ui.flashButton.setEnabled(False)

        # make_sd_log_file = os.path.join(self.download_path, "make_sd_card" + time.strftime("_%Y%m%d%H%M%S", time.localtime())+".log")

        make_sd_log_file = self.logfile

        # self.read_log_to_gui(make_sd_log_file)

        # todo: here to change dir is ok?
        os.chdir(self.download_path)
        self.flash_impl(make_sd_log_file)


    def read_agreement(self, dialog_agreement):

        if dialog_agreement.exec() == QDialog.Accepted:
            self.logger.info("you agree all the agreement of the package you download.")
            self.ui.checkBox_aggrement.setChecked(True)
            self.ui.pushButton.setEnabled(True)
        else:
            self.ui.checkBox_aggrement.setChecked(False)

        return

    def get_sd_name(self):

        usb_manager = USBManager()
        # usb_list = usb_manager.GetUsbName()
        usb_list = usb_manager.GetUsbName_by_fdisk(sudo_passwd=self.sudo_passwd)
        if len(usb_list) < 1:
            self.show_message("can't get any device, please check if you insert the SD Card correctedly, and turn the USB 3.0 feature on ?")
            self.getSDName_ui.comboBox.clear()
            return

        if usb_list[0] == '':
            self.show_message("can't get any device, please check if you insert the SD Card correctedly, and turn the USB 3.0 feature on ?")
        self.getSDName_ui.comboBox.clear()
        self.getSDName_ui.comboBox.addItems(usb_list)

    def prepare_pause(self):
        for t in self.download_thread_list:
            t.stop_flag = True
        self.logger.info("stop download thread")

        for t in self.apt_thread_list:
            t.stop_flag = True

        self.logger.info("stop apt thread")

        self.ui.pushButton_pause.setEnabled(False)
        self.ui.pushButton_pause.setVisible(False)
        self.ui.pushButton.setEnabled(True)
        self.ui.pushButton.setVisible(True)

        ADKUtils.disable_item_comboBox(self.ui.comboBox_apt, [0, 1, 2, 3, 4], 1 | 32)
        ADKUtils.disable_item_comboBox(self.ui.comboBox_tar, [0, 1], 1 | 32)

